// 封装通用的接口调用模块
// 导入axios组件
import axios from 'axios'
// 导入Vuex 实例化
import store from '@/store'
// 获取toekn
import { getToken, clearStorage, removeToken } from '@/utils/auth'
// 导入提示框
import { MessageBox } from 'element-ui'
// 导入序列化函数
import qs from 'qs'
// 导入Vue router 实例化
// import router from '@/router'
// 请求的基准路径 常量保存并且支持导出 通过process.env调用
const baseURL = process.env.VUE_APP_BASE_API

// 创建独立的axios的实例
const instance = axios.create({
  // baseURL是axios属性 用来声明url基础路径(比对上面声明的常量)
  baseURL: baseURL
  // 设置响应超时 建议不设置 或者设置时间较长 会影响一些较大的文件下载
  // timeout: 5000
})

// 请求拦截器 (发送数据前的加工数据)
instance.interceptors.request.use((config) => { // config是发送的数据
  // console.log(config)
  // 特殊处理headers传值（内容类型）
  // 判断Vuex中是否有token，如果有就添加到请求头
  const token = store.getters.token
  // 如果存在token 把token存入headers请求头中
  if (token) {
    //! config是发送的数据 headers是axios请求头
    config.headers['token'] = getToken()
  }
  // 返回处理后的数据
  return config
}, (err) => {
  // 如果请求拦截器错误 返回打印错误信息
  return Promise.reject(err)
})

// 响应拦截器 (处理后端返回的数据)
instance.interceptors.response.use((response) => {
  // 判断token是否失效 60001是token失效 60000是未登录(未携带token)
  if (response.data.code === 60001) {
    // to re-login
    MessageBox.confirm('用户登录信息过期，请重新登录！', '系统提示', {
      confirmButtonText: '登录',
      cancelButtonText: '取消',
      type: 'warning'
    }).then(() => {
      // 清空token
      clearStorage()
      // 清空cookie
      removeToken()
      // 刷新跳转
      window.location.href = '/login'
    }).catch(() => {
      // 清空token
      clearStorage()
      // 清空cookie
      removeToken()
      // 刷新跳转
      window.location.href = '/login'
    })
  } else if (response.data.code === 60000) {
    MessageBox.confirm('您未登录本系统 请从新登录！', '系统提示', {
      confirmButtonText: '登录',
      cancelButtonText: '取消',
      type: 'warning'
    }).then(() => {
      // 清空token
      clearStorage()
      // 清空cookie
      removeToken()
      // 刷新跳转
      window.location.href = '/login'
    }).catch(() => {
      // 清空token
      clearStorage()
      // 清空cookie
      removeToken()
      // 刷新跳转
      window.location.href = '/login'
    })
  } else {
    // 去除axios自带的一层data
    return response.data
  }
}, (err) => {
  console.log('失败')
  // // 处理token的过期操作
  // if (err.response && err.response.status === 401) {
  //   // ---------------------- 应该续签token 但是后端没做(按需设置)
  //   // token过期了，清空过期的用户信息，跳转到登录页面
  //   store.commit('user/updateUserInfo', {})
  //   // 跳转到登录页
  //   router.push('/login')
  // }
  // 打印响应拦截器的错误信息
  return Promise.reject(err)
})

//! 这里是只携带token请求头通用封装
// 封装一个通用的请求方法
export default (options) => {
  // 这里的返回值是Promise实例对象
  // return 返回数据 instance是声明的axios分支方法
  return instance({
    // 如果没有传递请求方式，默认是使用get请求
    method: options.method || 'GET',
    // 设置请求地址
    url: options.url,
    // 动态判断请求的方式(es6规则: 对象的键可以是动态的变量)
    // 如果不是data请求 那么就赋值params请求
    // api掉接口的时候 传递数据的属性名(键) 全部为data:{} (不管是那种方式)
    [options.method.toUpperCase() === 'GET' ? 'params' : 'data']: options.data // toUpperCase转换为大写(请求是小写也可以)
    // 设置请求头(一般用于跨域问题 和 传输token)
    // headers: options.headers // 不建议覆盖之前的headers 会出现问题 建议单独处理具备其他请求头的接口
  })
}

//! 这里是不光携带token还需要其他参数的特殊封装
// 名称要和api接口名称一致
const http = {

  //! 这里是特殊的post请求 通常需要携带参数
  // transformRequest是axios请求处理(拦截器还早) 允许在向服务器发送前 修改请求数据 通常会把数据转换为json格式
  // 这里是只能提交json数据 需要在请求头数据类型中设置类型为json
  postToken (url, params) {
    return instance.post(url, params, {
      transformRequest: [(params) => {
        return JSON.stringify(params)
      }],
      headers: {
        'Content-Type': 'application/json'
      }
    })
  },
  //! 这里是post请求不需要携带参数
  // 如果不需要参数 需要把参数2设置为null
  postNo (url) {
    return instance.post(url, null, {
      transformRequest: [(params) => {
        return JSON.stringify(params)
      }],
      headers: {
        'Content-Type': 'application/json'
      }
    })
  },
  //! 这里是获取arraybuffer类型的二进制数据 适用于验证码图片的获取 需要指定responseType类型
  // 他没有没有参数 在post请求时候参数需要写null 因为其不携带参数 否则无法转换
  getImage (url) {
    return instance.post(url, null, {
      responseType: 'arraybuffer'
    })
  },

  //! 这里是特殊的get请求 通常特殊处理的get请求需要携带参数 比如通过qs来实现序列化的函数
  // paramsSerializer是处理你向后端传递的数据 是一个负责向后端传递数据时序列化的函数
  qsToken (url, params) {
    return instance.get(url, {
      params: params,
      paramsSerializer: (params) => {
        // 通过qs处理序列化函数
        return qs.stringify(params, { arrayFormat: 'repeat' })
      }
    })
  }
  //! qs序列化的用法
  // qs.stringify({ids: [1, 2, 3]}, { indices: false })
  // 转换形式： ids=1 ids=2 id=3
  // qs.stringify({ids: [1, 2, 3]}, {arrayFormat: 'indices'})
  // 转换形式： ids[0]=1 ids[1]=2 ids[2]=3
  // qs.stringify({ids: [1, 2, 3]}, {arrayFormat: 'brackets'})
  // 转换形式：ids[]=1 ids[]=2 ids[]=3
  // qs.stringify({ids: [1, 2, 3]}, {arrayFormat: 'repeat'})
  // 转换形式： ids=1 ids=2 id=3
}

// 命名导出
export { http }

// --------------------------------- api接口上传数据模拟
// 所有的请求方式 上传数据的对象都设置为data:{} (在通用的请求方法中已配置)
// -------------- post请求方式
// return request({
//   method: 'post',
//   url: '#',
//   data: {
//     uname: 'lisi',
//     pwd: '123'
//   }
// })
// -------------- get 请求方式
// return request({
//   method: 'get',
//   url: '#',
//   data: {
//     uname: 'lisi',
//     pwd: '123'
//   }
// })
